package org.pc2r.protocole;

import java.util.Arrays;
import java.util.List;

import org.pc2r.exception.PC2RException;
import org.pc2r.game.model.Position;
import org.pc2r.protocole.message.PutShipMessage;
import org.pc2r.protocole.message.WelcomeConnectMessage;

public final class RequestBuilder {

  static public final String SEPARATOR = "/";
  static public final String END = "\n";
	static final public int MIN_X = 0;
	static final public int MAX_X = 15;
	static final public char MIN_Y = 'A';
	static final public char MAX_Y = 'P';

  public static boolean isPlayerAgain(String request) {
    return request.equals(EnumRequest.PLAYAGAIN + SEPARATOR + END);
  }
	
  public static String[] parseAction(String request, int nbAction) throws PC2RException {
	  if(request.startsWith(EnumRequest.ACTION.toString()) == false) {
		  throw new PC2RException("N'est pas un message de type action - \"" + request + "\"");
	  }
	  String[] split = request.split(SEPARATOR);
	  if (split.length != (2 + nbAction))
	      throw new PC2RException("Message mal formé, on veut " + nbAction + " actions : " + request);
	    
	  // On enlève les arguments inutiles
	   return Arrays.copyOfRange(split, 1, split.length - 1);
  }
	
  public static WelcomeConnectMessage parseConnect(String request) throws PC2RException {
    if (request.startsWith(EnumRequest.CONNECT.toString()) == false)
      throw new PC2RException("N'est pas un message de type connexion - \"" + request + "\"");

    // On récupère le 1er /
    int position = request.indexOf(SEPARATOR);
    if (position == -1) {
      throw new PC2RException("Il n'y a pas de " + SEPARATOR + " : " + request);
    }
    // On récupère le deuxième /
    int lastIndexOf = request.lastIndexOf(SEPARATOR);
    if (position == lastIndexOf) {
      throw new PC2RException("Il n'y a pas de " + SEPARATOR + " à la fin : " + request);
    }
    // On récupère le nom et on renvoie la requête
    String name = request.substring(++position, lastIndexOf);
    if (name == null || name.isEmpty())
      throw new PC2RException("Il n'y a pas de login");
    return new WelcomeConnectMessage(EnumRequest.CONNECT, name);
  }

  public static PutShipMessage parsePutShip(String request, int size) throws PC2RException {
    // On vérifie que ca commence bien par putship
    if (request.startsWith(EnumRequest.PUTSHIP.toString()) == false) {
      throw new PC2RException("Le message n'est pas un putship " + request);
    }
    String[] fakeSplit = request.split(SEPARATOR);
    // Si même pas 2 arguments, c'est faux
    if (fakeSplit.length < 2)
      throw new PC2RException("Message mal formé : " + request);
    
    // On enlève le PUTSHIP et le \n pour récupérer les arguments purs
    String[] split = Arrays.copyOfRange(fakeSplit, 1, fakeSplit.length - 1);
    // on a dit un sous marin de taille "size" donc on doit avoir "size * 2" arguments
    if (split.length != (2 * size))
      throw new PC2RException("On désire placer un sous-marin de taille " + size + " : " + request + ". La taille est invalide.");

    PutShipMessage put = new PutShipMessage();
    for (int i = 0; i < 2 * size ; i += 2) {
      // On récupère la première position et on l'ajoute. On en profite pour valider 
      // la syntaxe, les bornes, ...
      boolean addPosition = put.addPosition(split[i], split[i + 1]);
      if (false == addPosition)
        throw new PC2RException("Message mal formé : " + request);
    }
    // On vérifie que l'ensemble des positions est cohérente (horizontal ou verticale sur une ligne)
    if(checkIsHorizontal(put)) {
      put.setHorizontal(true);
    }
    return put;
  }
  
  static private boolean checkIsHorizontal(PutShipMessage put) throws PC2RException {
    List<Position> positions = put.getPositions();
    int size = positions.size();
    if(size == 1) return true;
    
    boolean isHorizontal = positions.get(0).isHorizontal(positions.get(1));
    // On vérifie que toutes les positions se suivent    
    Position previous = positions.get(0);
    for(int i = 1 ; i < size ; i++) {
      Position position = positions.get(i);
      // On vérifie que la position est la suivante de previous (en X ou en Y)
      if(previous.isNext(position) == false) {
        throw new PC2RException("Les positions ne se suivent pas : " + positions);
      }
      // On vérifie aussi qu'elles se suivent dans la même direction. On évite le cas de "1A / 2A / 3B"
      // où à l'horizontal elles se suivent mais la dernière case est en diagonale
      if(previous.isHorizontal(position) != isHorizontal) {
        throw new PC2RException("Les positions ne se suivent pas : " + positions);
      }
      previous = position;
    }
    return isHorizontal;
  }

  private RequestBuilder() {
  }

}
